home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 7 / BBS in a Box - Macintosh - Volume VII (BBS in a Box) (January 1993).iso / Files / Prog / U-Z / Viewer.src.cpt / FileDisplay.c next >
Encoding:
C/C++ Source or Header  |  1987-12-31  |  13.1 KB  |  636 lines  |  [TEXT/KAHL]

  1. /* FileDisplay - maintain a TERec of what's on the screen from a long file
  2.     messages:
  3.         FD_New        Create a new record, return handle in (FDHandle) *arg1
  4.                     Read from file (LFile *) arg2
  5.                     To be displayed in current window, inside
  6.                     (Rect *) arg3
  7.                     Tabs set to (long) arg4
  8.                     Reads initial part of file
  9.                     Can assume starting location is 0
  10.  
  11. All of the rest take an FDHandle as arg1; if it's NULL, nothing is done
  12.  
  13.         FD_Redraw    Read from line at offset (long) arg3 from one
  14.                     containing char (long *) arg2,
  15.                     redraw the screen, return in arg2 the actual start
  16.  
  17.         FD_Scroll    Scroll (long) arg2 pixels right & (long) arg3 lines
  18.                     down (left or up if negative) (redraws screen)
  19.                     returns starting char# in (long *) arg4
  20.                     >>> arg3 should be either -1, 0, or +1 <<<
  21.                     (this is enforced by the routine)
  22.  
  23.         FD_Resize    Window has been resized, so update data
  24.                     (Rect *) arg2 has rectangle to show text in
  25.  
  26.         FD_SetTabs    Set tabs to (long) arg2
  27.  
  28.         FD_Update    Handle update event (caller has called beginupdate)
  29.         
  30.         FD_Click    Handle mousedown events
  31.                     (Event *) arg2 is the event
  32.  
  33.         FD_Dispose    Dispose of the record
  34.         
  35.         FD_Copy        Copy selection to clipboard
  36.         
  37.         FD_Activate    Activate or deactivate record in response to activate
  38.                         event
  39.                     (long) arg2 is nonzero iff activate
  40.  
  41.         FD_Idle        Call often to make caret blink
  42.                     Must use this, not teidle, to get tabs handled correctly
  43.  
  44. Needs an external routine, GenError( str1, str2, str3, str4 ); whose
  45. arguments are Pascal strings
  46. */
  47.  
  48. #include <Quickdraw.h>
  49. #include <ScrapMgr.h>
  50. #include <TextEdit.h>
  51. #include <FileMgr.h>
  52. #include <EventMgr.h>
  53. #include <strings.h>
  54. #include "LineFile.h"
  55. #include "FileDisplay.h"
  56.  
  57. #define NULL 0L
  58.  
  59. #define MAXLINES(H) ( (**(H)).viewRect.bottom - (**(H)).viewRect.top ) \
  60.                         / (**(H)).lineHeight
  61.  
  62. #define ALLOCSIZE 1000L
  63.  
  64. /* the following globals are used by call-back procedures: */
  65.  
  66. static ProcPtr        report_proc;
  67. static FDHandle        theFD;
  68. static QDProcs        lowqdprocs;
  69. static int            tab_size;
  70.  
  71. void New();
  72. void Redraw();
  73. void Scroll();
  74. void Resize();
  75. void SetTabs();
  76. void Update();
  77. void Click();
  78. void Dispose();
  79. void Copy();
  80. void Activate();
  81. void Rec_Activate();
  82. void Idle();
  83.  
  84. void FileDisplay( message, hFD, arg2, arg3, arg4 )
  85. int message;
  86. register long hFD, arg2, arg3, arg4;
  87. {
  88.     if ( message != FD_New )
  89.         if ( hFD == NULL )
  90.             return;
  91.         else
  92.             patchtabs( hFD );
  93.  
  94.     switch ( message ) {
  95.         case FD_New:
  96.             New( hFD, arg2, arg3, arg4 );
  97.             break;
  98.  
  99.         case FD_Redraw:
  100.             Redraw( hFD, arg2, arg3 );
  101.             break;
  102.  
  103.         case FD_Scroll:
  104.             Scroll( hFD, arg2, arg3, arg4 );
  105.             break;
  106.  
  107.         case FD_Resize:
  108.             Resize( hFD, arg2 );
  109.             break;
  110.  
  111.         case FD_SetTabs:
  112.             SetTabs( hFD, arg2 );
  113.             break;
  114.  
  115.         case FD_Update:
  116.             Update( hFD );
  117.             break;
  118.  
  119.         case FD_Click:
  120.             Click( hFD, arg2 );
  121.             break;
  122.  
  123.         case FD_Dispose:
  124.             Dispose( hFD );
  125.             break;
  126.  
  127.         case FD_Copy:
  128.             Copy( hFD );
  129.             break;
  130.  
  131.         case FD_Activate:
  132.             Activate( hFD, arg2 );
  133.  
  134.         case FD_Idle:
  135.             Idle( hFD );
  136.         }
  137.  
  138.     if ( message != FD_Dispose && message != FD_New )
  139.         unpatchtabs( hFD );
  140. }
  141.  
  142. Boolean memok()
  143. {
  144.     register int err;
  145.     char errs[256];
  146.     
  147.     if ( ( err = MemError() ) != noErr ) {
  148.         NumToString( (long) err, errs );
  149.         GenError( "\pMemory Error ", errs, "\p", "\p" );
  150.         return FALSE;
  151.         }
  152.  
  153.     return TRUE;
  154. }
  155.  
  156. static Boolean sel_in_view( hFD )
  157. register FDHandle hFD;
  158. {
  159.     register long first, last;
  160.     
  161.     if ( (**hFD).actuallines == 0 ) return FALSE;
  162.  
  163.     first = (**hFD).filestarts[ 0 ];
  164.     last = first + (**(**hFD).TE).teLength;
  165.     
  166.     return ( (**hFD).sel_start < last && (**hFD).sel_end > first ) ||
  167.            ( (**hFD).sel_start == first && (**hFD).sel_end == first );
  168. }
  169.  
  170. static void set_te_select( hFD )
  171. register FDHandle hFD;
  172. {
  173.     register long        first, length, selstart, selend;
  174.     register TEHandle    hTE = (**hFD).TE;
  175.  
  176.     if ( (**hFD).actuallines == 0 ) return;
  177.     
  178.     first = (**hFD).filestarts[ 0 ];
  179.     length = (**hTE).teLength;
  180.  
  181.     selstart = (**hFD).sel_start - first;
  182.     selend = (**hFD).sel_end - first;
  183.     
  184.     if ( selstart < 0L )
  185.         selstart = 0L;
  186.     else if ( selstart > length )
  187.         selstart = length;
  188.  
  189.     if ( selend < 0L )
  190.         selend = 0L;
  191.     else if ( selend > length )
  192.         selend = length;
  193.  
  194.     (**hTE).selStart = selstart;
  195.     (**hTE).selEnd = selend;
  196. }
  197.  
  198. static void FillFD( hFD, pos, offset )
  199. register FDHandle hFD;
  200. long pos, offset;
  201. {
  202.     register int    i,
  203.                     max = (**hFD).maxlines;
  204.     register long    length,
  205.                     totlength;
  206.     char            **newtext, 
  207.                     newline[256];
  208.     register TEHandle    hTE = (**hFD).TE;
  209.     
  210.     SetHandleSize( hFD, (long) sizeof( FDRec ) + sizeof( long ) * max );
  211.     if ( !memok() ) return;
  212.  
  213.     newtext = (char **) NewHandle( 0L );
  214.     if ( !memok() ) return;
  215.     totlength = 0L;
  216.  
  217.     for ( i = 0; i < max; ++i, offset = 1L ) {
  218.         LineFile( LF_GetLine, &(**hFD).file, pos, offset, newline, &pos );
  219.         length = strlen( newline );
  220.  
  221.         if ( length == 0 )
  222.             if ( i == 0 && offset < 0 ) {
  223.                 LineFile( LF_GetLine, &(**hFD).file, 0L, 0L, newline, &pos );
  224.                 if ( ( length = strlen( newline ) ) == 0 )
  225.                     break;
  226.                 }
  227.             else
  228.                 break;
  229.  
  230.         (**hFD).filestarts[ i ] = pos;
  231.  
  232.         SetHandleSize( newtext, totlength + length );
  233.         if ( !memok() ) {
  234.             DisposHandle( newtext );
  235.             return;
  236.             }
  237.  
  238.         BlockMove( newline, *newtext + totlength, length );
  239.         totlength += length;
  240.         }
  241.  
  242.     if ( totlength != 0 ) {
  243.         if ( (**hTE).hText != NULL )
  244.             DisposHandle( (**hTE).hText );
  245.         (**hTE).hText = newtext;
  246.         TECalText( hTE );
  247.         (**hFD).actuallines = i;
  248.         set_te_select( hFD );
  249.         }
  250. }
  251.  
  252. static void New( phFD, lfile, viewrect, tsize )
  253. register FDHandle *phFD;
  254. LFile *lfile;
  255. Rect *viewrect;
  256. long tsize;
  257. {
  258.     register FDPtr pFD;
  259.     Rect destrect;
  260.  
  261.     *phFD = (FDHandle) NewHandle( (long) sizeof( FDRec ) );
  262.     if ( !memok() ) return;
  263.  
  264.     HLock( *phFD );
  265.     pFD = **phFD;
  266.  
  267.     destrect = *viewrect;
  268.     destrect.left += BORDER;
  269.     destrect.right = 20000;
  270.     
  271.     if ( ( pFD->TE = TENew( &destrect, viewrect ) ) == NULL ) {
  272.         HUnlock( *phFD );
  273.         DisposHandle( *phFD );
  274.         *phFD = NULL;
  275.         return;
  276.         }
  277.  
  278.     (**pFD->TE).crOnly = -1;
  279.  
  280.     pFD->tabsize = tsize;
  281.     pFD->file = *lfile;
  282.  
  283.     pFD->sel_start = pFD->sel_end = 0L;
  284.  
  285.     pFD->maxlines = MAXLINES( pFD->TE );
  286.     (**pFD->TE).viewRect.bottom =
  287.          viewrect->top + pFD->maxlines * (**pFD->TE).lineHeight;
  288.  
  289.     HUnlock( *phFD );
  290.  
  291.     FillFD( *phFD, 0L, 0L );
  292. }
  293.  
  294. static void Redraw( hFD, startpos, offset )
  295. register FDHandle hFD;
  296. register long *startpos;
  297. long offset;
  298. {
  299.     FillFD( hFD, *startpos, offset );
  300.     if ( (**hFD).actuallines > 0 )
  301.         *startpos = (**hFD).filestarts[ 0 ];
  302.     else
  303.         *startpos = 0L;
  304.  
  305.     Update( hFD );
  306.     Activate( hFD, 1L );
  307. }
  308.  
  309. static void Scroll( hFD, dh, dv, startpos )
  310. register FDHandle hFD;
  311. register long dv;
  312. long dh, *startpos;
  313. {
  314.     char            newline[ 256 ];
  315.     register long     totlength, 
  316.                     newlength,
  317.                     lengthremoved;
  318.     long            pos,
  319.                     newlinestart;
  320.     int                max = (**hFD).maxlines;
  321.     TEHandle        hTE = (**hFD).TE;
  322.     register Handle    thetext = (**hTE).hText;
  323.     RgnHandle        updatergn,
  324.                     oldclip;
  325.     Rect            srect;
  326.     GrafPtr            oldport;
  327.  
  328.     GetPort( &oldport );
  329.     SetPort( (**hTE).inPort );
  330.     oldclip = NewRgn();
  331.     GetClip( oldclip );
  332.  
  333.     *startpos = (**hFD).filestarts[ 0 ];
  334.  
  335.     if ( dv != 0 ) {
  336.         dv = ( dv < 0 ) ? -1L : 1L;
  337.  
  338.         pos = ( (**hFD).actuallines == 0 ) ?
  339.                     0L
  340.               : ( dv > 0 ) ?
  341.                       (**hFD).filestarts[ 0 ]
  342.               :        (**hFD).filestarts[ (**hFD).actuallines - 1 ];
  343.  
  344.         LineFile( LF_GetLine, &(**hFD).file, pos, -dv,
  345.                         newline, &newlinestart );
  346.  
  347.         newlength = strlen( newline );
  348.         totlength = (**hTE).teLength;
  349.  
  350.         if ( newlength != 0 ) {
  351.             lengthremoved =
  352.                 ( (**hFD).actuallines < max ) ?
  353.                     0L
  354.                 : ( dv > 0 ) ?
  355.                     totlength - (**hTE).lineStarts[ max - 1 ]
  356.                 : ( max < 2 ) ?
  357.                     totlength
  358.                 :    (**hTE).lineStarts[ 1 ];
  359.  
  360.             SetHandleSize( thetext, totlength + newlength );
  361.             if ( !memok() ) return;
  362.             totlength -= lengthremoved;
  363.         
  364.             if ( dv > 0 ) {
  365.                 BlockMove( *thetext, *thetext + newlength, totlength );
  366.                 BlockMove( newline, *thetext, newlength );
  367.                 BlockMove( (**hFD).filestarts, (**hFD).filestarts + 1,
  368.                             (long) sizeof( long ) * ( max - 1 ) );
  369.                 if ( (**hFD).actuallines < max )
  370.                     ++(**hFD).actuallines;
  371.                 (**hFD).filestarts[ 0 ] = newlinestart;
  372.                 }
  373.             else {
  374.                 BlockMove( *thetext + lengthremoved, *thetext, totlength );
  375.                 BlockMove( newline, *thetext + totlength, newlength );
  376.                 BlockMove( (**hFD).filestarts + 1, (**hFD).filestarts,
  377.                             (long) sizeof( long ) * ( max - 1 ) );
  378.                 (**hFD).filestarts[ max - 1 ] = newlinestart;
  379.                 }
  380.             
  381.             SetHandleSize( thetext, totlength + newlength );
  382.             TECalText( hTE );
  383.             set_te_select( hFD );
  384.             *startpos = (**hFD).filestarts[ 0 ];
  385.             }
  386.  
  387.         else                /* newlength == 0 */
  388.             dv = 0L;
  389.         }
  390.  
  391.     if ( dv != 0L || dh != 0L ) {
  392.         srect = (**hTE).viewRect;
  393.         updatergn = NewRgn();
  394.         ScrollRect( &srect, (int) dh, (int) dv * (**hTE).lineHeight, updatergn );
  395.     
  396.         OffsetRect( &(**hTE).destRect, (int) dh, 0 );
  397.     
  398.         SetClip( updatergn );
  399.         srect = (**updatergn).rgnBBox;
  400.         TEUpdate( &srect, hTE );
  401.         Activate( hFD, 1L );
  402.         DisposeRgn( updatergn );
  403.         }
  404.         
  405.     SetClip( oldclip );
  406.     SetPort( oldport );
  407.     
  408.     DisposeRgn( oldclip );
  409. }
  410.  
  411. static void Resize( hFD, viewrect )
  412. register FDHandle hFD;
  413. Rect *viewrect;
  414. {
  415.     register TEHandle    hTE = (**hFD).TE;
  416.     int                    dest_offset;
  417.  
  418.     dest_offset = (**hTE).destRect.left - (**hTE).viewRect.left;
  419.     
  420.     (**hTE).destRect = (**hTE).viewRect = *viewrect;
  421.     (**hTE).destRect.left += dest_offset;
  422.     (**hTE).destRect.right = 20000;
  423.     
  424.     (**hFD).maxlines = MAXLINES( hTE );
  425.     (**hTE).viewRect.bottom = viewrect->top
  426.                     + (**hFD).maxlines * (**hTE).lineHeight;
  427.  
  428.     FillFD( hFD, (**hFD).filestarts[ 0 ], 0L );
  429.     Activate( hFD, 1L );
  430. }
  431.  
  432. static void SetTabs( hFD, size )
  433. register FDHandle hFD;
  434. long size;
  435. {
  436.     register TEHandle    hTE = (**hFD).TE;
  437.     GrafPtr                oldport,
  438.                         port = (**hTE).inPort;
  439.     Rect                vrect;
  440.  
  441.     GetPort( &oldport );
  442.     SetPort( port );
  443.  
  444.     (**hFD).tabsize = size;
  445.     
  446.     vrect = (**hTE).viewRect;
  447.     InvalRect( &vrect );
  448.     
  449.     SetPort( oldport );
  450. }
  451.  
  452. static void Update( hFD )
  453. FDHandle hFD;
  454. {
  455.     Rect updaterect;
  456.     register TEHandle hTE = (**hFD).TE;
  457.     
  458.     updaterect = (**hTE).viewRect;
  459.     EraseRect( &updaterect );
  460.     TEUpdate( &updaterect, hTE );
  461. }
  462.  
  463. pascal void tabs_textproc( size, text, numer, denom )
  464. int size;
  465. char *text;
  466. Point numer, denom;
  467. {
  468.     int newsize;
  469.     char *newtext;
  470.  
  471.     SetUpA4();
  472.     
  473.     convertabs( size, text, &newsize, &newtext );
  474.     
  475.     StdText( newsize, newtext, numer, denom );
  476.     
  477.     DisposPtr( newtext );
  478.     
  479.     RestoreA4();
  480. }
  481.  
  482. pascal int tabs_txmeasproc( size, text, numer, denom, info )
  483. int size;
  484. char *text;
  485. Point *numer, *denom;
  486. Ptr info;
  487. {
  488.     int newsize;
  489.     register int length;
  490.     char *newtext;
  491.     
  492.     SetUpA4();
  493.     
  494.     convertabs( size, text, &newsize, &newtext );
  495.     
  496.     length = StdTxMeas( newsize, newtext, numer, denom, info );
  497.     
  498.     DisposPtr( newtext );
  499.     
  500.     RestoreA4();
  501.     
  502.     return length;
  503. }
  504.  
  505. convertabs( oldsize, oldtext, newsize, newtext )
  506. int oldsize, *newsize;
  507. register char oldtext[], **newtext;
  508. {
  509.     register int i, j, numtabs, stop;
  510.     
  511.     for ( i = 0, numtabs = 0; i < oldsize; ++i )
  512.         if ( oldtext[ i ] == '\t' ) ++numtabs;
  513.         
  514.     *newsize = oldsize + numtabs * ( tab_size - 1 );
  515.  
  516.     *newtext = (char *) NewPtr( (long) *newsize );
  517.     
  518.     for ( i = 0, j = 0; i < oldsize; ++i )
  519.         if ( oldtext[ i ] == '\t' ) {
  520.              stop = ( j / tab_size + 1 ) * tab_size;
  521.              for ( ; j < stop; ++j )
  522.                   (*newtext)[ j ] = ' ';
  523.               }
  524.           else
  525.               (*newtext)[ j++ ] = oldtext[ i ];
  526.      
  527.     *newsize = j;
  528. }
  529.  
  530. patchtabs( hFD )
  531. FDHandle hFD;
  532. {
  533.     SetStdProcs( &lowqdprocs );
  534.     lowqdprocs.textProc = ( QDPtr ) tabs_textproc;
  535.     lowqdprocs.txMeasProc = ( QDPtr ) tabs_txmeasproc;
  536.  
  537.     (**(**hFD).TE).inPort->grafProcs = &lowqdprocs;
  538.     tab_size = (**hFD).tabsize;
  539. }
  540.  
  541. unpatchtabs( hFD )
  542. FDHandle hFD;
  543. {
  544.     (**(**hFD).TE).inPort->grafProcs = NULL;
  545. }
  546.  
  547. static void Click( hFD, theEvent )
  548. register FDHandle hFD;
  549. EventRecord *theEvent;
  550. {
  551.     Point                where;
  552.     register TEHandle    hTE = (**hFD).TE;
  553.     Boolean                extendp;
  554.     long                start, length;
  555.     
  556.     theFD = hFD;
  557.     
  558.     extendp = ( ( theEvent->modifiers & shiftKey ) != 0 );
  559.     
  560.     where = theEvent->where;
  561.     GlobalToLocal( &where );
  562.     
  563.     TEActivate( hTE );
  564.     TEClick( where, extendp, hTE );
  565.  
  566.     start = (**hFD).filestarts[ 0 ];
  567.     length = (**hTE).teLength;
  568.  
  569.     if ( !extendp || (**hFD).sel_start >= start ) 
  570.         (**hFD).sel_start = start + (**hTE).selStart;
  571.     if ( !extendp || (**hTE).selEnd < length || (**hFD).sel_end < length )
  572.         (**hFD).sel_end = start + (**hTE).selEnd;
  573. }
  574.  
  575. static void Dispose( hFD )
  576. register FDHandle hFD;
  577. {
  578.     if ( hFD != NULL ) {
  579.         TEDispose( (**hFD).TE );
  580.         HLock( hFD );
  581.         LineFile( LF_Close, &(**hFD).file );
  582.         HUnlock( hFD );
  583.         DisposHandle( hFD );
  584.         }
  585. }
  586.  
  587. static void Copy( hFD )
  588. register FDHandle hFD;
  589. {
  590.     int err;
  591.     char errs[256];
  592.     register Ptr temp_scrap;
  593.     long length;
  594.     
  595.     if ( ( length = (**hFD).sel_end - (**hFD).sel_start ) == 0L ) return;
  596.     
  597.     temp_scrap = NewPtr( length );
  598.     if ( !memok() ) return;
  599.     
  600.     err = SetFPos( (**hFD).file.refnum, fsFromStart, (**hFD).sel_start );
  601.     if ( err != noErr ) {
  602.         NumToString( (long) err, errs );
  603.         GenError( "\pError writing to Clipboard: ", errs, "\p", "\p" );
  604.         }
  605.  
  606.     err = FSRead( (**hFD).file.refnum, &length, temp_scrap );
  607.     if ( err != noErr && err != eofErr ) {
  608.         NumToString( (long) err, errs );
  609.         GenError( "\pError writing to Clipboard: ", errs, "\p", "\p" );
  610.         }
  611.  
  612.     ZeroScrap();
  613.     if ( ( err = PutScrap( length, 'TEXT', temp_scrap ) ) != noErr ) {
  614.         NumToString( (long) err, errs );
  615.         GenError( "\pError writing to Clipboard: ", errs, "\p", "\p" );
  616.         }
  617.  
  618.     DisposPtr( temp_scrap );
  619. }
  620.  
  621. static void Activate( hFD, which )
  622. register FDHandle hFD;
  623. long which;
  624. {
  625.     if ( which != 0 && sel_in_view( hFD ) )
  626.         TEActivate( (**hFD).TE );
  627.     else
  628.         TEDeactivate( (**hFD).TE );
  629. }
  630.  
  631. static void Idle( hFD )
  632. FDHandle hFD;
  633. {
  634.     TEIdle( (**hFD).TE );
  635. }
  636.